package xx.stream.use;

import lombok.AllArgsConstructor;
import lombok.Data;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * @Classname StreamUse
 * @Description TODO
 * @Date 2023/7/21 17:32
 * @Created by wangxianlin
 */
public class StreamUse {

    public static void main(String[] args) {
        flatMap();
    }


    /** TODO **************************************  filter **************************************  */

    /**
     * 起过滤筛选的作用。内部就是Predicate接口。惰性求值。
     */
    public static void filter() {
        List<String> tempList = Arrays.asList("小芳", "小李", "小林", "小王");
        List<String> resList = tempList.stream()
                .filter(s -> s.contains("王"))
                .collect(Collectors.toList());
        System.out.println(resList.toString());
    }

    /**
     * TODO **************************************  map **************************************
     */

    public static void map() {
        List<String> tempList = Arrays.asList("小芳", "小李", "小林", "小王");
        List<String> resList = tempList.stream()
                .map(s -> "姓名: " + s)
                .collect(Collectors.toList());
        System.out.println(resList.toString());
    }

    /**
     * TODO **************************************  flatmap **************************************
     */
    @Data
    static class Personnel {
        // 人员姓名
        private String name;
        // 人员标签
        private List<String> tagList;

        public Personnel(String name, List<String> tagList) {
            this.name = name;
            this.tagList = tagList;
        }
    }

    public static void flatMap(){
        Personnel personA = new Personnel("张三", Arrays.asList("抽烟", "喝酒", "烫头"));
        Personnel personB = new Personnel("李斯", Arrays.asList("编码", "喝酒", "踢足球"));
        List<Personnel> personnelList = Arrays.asList(personA, personB);
        personnelList.stream()
                .flatMap(p -> p.getTagList().stream())
                .forEach(s -> System.out.print(s + " "));
    }




    /**
     * TODO **************************************  distinct **************************************
     */

    public static void distinct() {
        List<Integer> numList = Arrays.asList(1, 1, 1, 1, 2, 3, 2, 2);
        List<Integer> distinctList = numList.stream()
                .distinct()
                .collect(Collectors.toList());
        System.out.println(distinctList);
    }

    /**
     * TODO **************************************  sorted **************************************
     */

    public static void sorted() {
        List<Integer> numList = Arrays.asList(10, 20, 18, 300, 30, 2);
        // ① 默认排序
        List<Integer> orderList = numList.stream()
                .sorted()
                .collect(Collectors.toList());
        System.out.printf("① 默认排序: %s%n", orderList);
        // ② 自定义排序
        List<Integer> orderDescList = numList.stream()
                .sorted((x, y) -> {
                    return y.compareTo(x);
                })
                .collect(Collectors.toList());
        System.out.printf("② 自定义排序: %s%n", orderDescList);
    }

    /**
     * TODO **************************************  limit **************************************
     */

    public static void limit() {
        List<Integer> numList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
        List<Integer> limitList = numList.stream()
                .limit(4)
                .collect(Collectors.toList());
        System.out.println(limitList);
    }

    /**
     * TODO **************************************  skip **************************************
     */

    public static void skip() {
        List<Integer> numList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
        List<Integer> skipList = numList.stream()
                .skip(numList.size() - 2)
                .collect(Collectors.toList());
        System.out.println(skipList);
    }


    /**
     * TODO **************************************  peek **************************************
     */

    public static void peek() {
        List<Integer> numList = Arrays.asList(5, 6, 7, 8);
        List<Integer> resList = numList.stream()
                .peek(System.out::println)
                .filter(s -> s == 5)
                .peek(s -> System.out.printf("过滤后的:%d%n", s))
                .collect(Collectors.toList());
    }

    /**
     * TODO **************************************  forEach **************************************
     */

    public static void forEach() {
        // 给公司工资普涨 500
        List<Integer> salaryList = Arrays.asList(12000, 20000, 30000, 4000);
        salaryList.stream()
                .peek(s -> System.out.print("工资普涨前:" + s))
                .map(s -> s + 500)
                .forEach(s -> {
                    System.out.println("--工资普涨后:" + s);
                });
    }

    /**
     * TODO **************************************  collect **************************************
     */

    public static void collectTest() {
        List<User> userList = Arrays.asList(new User("张三", 2000.5),
                new User("李斯", 11000.5),
                new User("王二", 12000.5),
                new User("张六", 32000.5),
                new User("赵公子", 1000000.0));
        Map<String, Double> userSalaryMap = userList.stream()
                .collect(Collectors.toMap(User::getName, User::getSalary));
        userSalaryMap.forEach((k, v) -> {
            System.out.printf("姓名:%s,工资:%.2f%n", k, v);
        });
    }

    @Data
    @AllArgsConstructor
    static class User {
        private String name;
        private Double salary;
    }

    /**
     * TODO **************************************  toArray **************************************
     */

    public static void toArray() {
        // 示例整数流
        IntStream intStream = IntStream.of(1, 2, 3, 4, 5);
        // 使用toArray()将流中的元素收集到一个数组中
        int[] intArray = intStream.toArray();
        // 输出结果数组
        System.out.println(Arrays.toString(intArray));
    }

    /**
     * TODO **************************************  reduce **************************************
     */

    public static void reduceTest() {
        // 示例整数流
        IntStream intStream = IntStream.of(1, 2, 3, 4, 5);
        // 使用reduce()将流中的整数相加得到总和
        OptionalInt sumOptional = intStream.reduce((a, b) -> a + b);

        // 获取结果总和，如果流为空，则给出一个默认值0
        int sum = sumOptional.orElse(0);
        // 输出结果总和
        System.out.println("总和: " + sum);
    }

    /**
     * TODO **************************************  min / max **************************************
     */

    public static void minAndMaxTest() {
        // 示例整数流
        Stream<Integer> integerStream = Stream.of(1, 5, 3, 8, 2);

        // 使用min()找到最小值
        Optional<Integer> minOptional = integerStream.min(Integer::compareTo);
        if (minOptional.isPresent()) {
            System.out.println("最小值为: " + minOptional.get());
        } else {
            System.out.println("流为空.");
        }

        // 重新创建一个整数流，因为流已被消耗
        Stream<Integer> newIntegerStream = Stream.of(1, 5, 3, 8, 2);

        // 使用max()找到最大值
        Optional<Integer> maxOptional = newIntegerStream.max(Integer::compareTo);
        if (maxOptional.isPresent()) {
            System.out.println("最大值为: " + maxOptional.get());
        } else {
            System.out.println("流为空.");
        }
    }

    /**
     * TODO **************************************  count **************************************
     */

    public static void countTest() {
        List<Integer> numList = Arrays.asList(11, 22, 1, 2, 3, 4, 6, 33, 44, 553);
        long count = numList.stream().filter(s1 -> s1 > 10).count();
        System.out.println("大于10的个数数是：" + count);
    }

    /**
     * TODO **************************************  anyMatch / allMatch / noneMatch **************************************
     */

    public static void matchTest() {
        // 示例整数流
        Stream<Integer> integerStream = Stream.of(1, 5, 3, 8, 2);

        // 使用anyMatch()检查是否存在元素大于5
        boolean anyGreaterThan5 = integerStream.anyMatch(num -> num > 4);
        System.out.println("是否存在元素大于 5 ?" + anyGreaterThan5);

        // 重新创建一个整数流，因为流已被消耗
        Stream<Integer> newIntegerStream = Stream.of(1, 5, 3, 8, 2);

        // 使用allMatch()检查是否所有元素都小于10
        boolean allLessThan10 = newIntegerStream.allMatch(num -> num < 10);
        System.out.println("所有元素都小于10 ? " + allLessThan10);

        // 重新创建一个整数流，因为流已被消耗
        Stream<Integer> newestIntegerStream = Stream.of(1, 5, 3, 8, 2);

        // 使用noneMatch()检查是否没有元素等于10
        boolean noneEqualTo10 = newestIntegerStream.noneMatch(num -> num == 10);
        System.out.println("是否没有元素等于 10 ? " + noneEqualTo10);
    }

    /**
     * TODO **************************************  findFirst / findAny **************************************
     */

    public static void findStreamTest () {
        // 示例整数流
        Stream<Integer> integerStream = Stream.of(1, 5, 3, 8, 2);

        // 使用findFirst()找到第一个元素
        Optional<Integer> firstElementOptional = integerStream.findFirst();
        if (firstElementOptional.isPresent()) {
            System.out.println("发现第一个元素: " + firstElementOptional.get());
        } else {
            System.out.println("流为空!");
        }

        // 重新创建一个整数流，因为流已被消耗
        Stream<Integer> newIntegerStream = Stream.of(1, 5, 3, 8, 2);

        // 使用findAny()找到任意一个元素
        Optional<Integer> anyElementOptional = newIntegerStream.findAny();
        if (anyElementOptional.isPresent()) {
            System.out.println("找到任意一个元素: " + anyElementOptional.get());
        } else {
            System.out.println("流为空!");
        }
    }


    /**
     * TODO **************************************  reduce **************************************
     */

    public static void reduce() {
        Integer reduce = Stream.of(1, 2, 3, 4).reduce(0, (acc, x) -> acc + x);
        System.out.println(reduce);
    }
}
